package com.sz.app.customer.api;

import com.sz.biz.app.dto.LoginDataDto;
import com.sz.biz.common.constants.MessagesCodes;
import com.sz.common.base.dto.ResultDto;
import com.sz.common.base.i18n.I18nMessages;
import com.sz.app.customer.exception.ErrorCodes;

import io.swagger.annotations.Api;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Base64;

/**
 * Function: VCodeController <br>
 * Author: Charles <br>
 * Date: 2016-11-16 17:28:00
 */
@Controller
@RequestMapping("/api/v1/auth")
@Api(description = " ", tags = "000-0、安全登录")
public class VCodeController {

    private static final String VCODE_KEY = "checkcode";
    private static final String TEXT_BASE64 = "text/base64";
    private static final String UTF_8 = "UTF-8";
    private static final String JPG = "jpg";

    @Autowired
    protected I18nMessages messageSource;

    @RequestMapping(value = "/login/getcodeimage", method = RequestMethod.GET)
    public void getCodeImage(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        int width = 150;
        int height = 45;
        // 将随机数存在session中
        String code = generateNewRandom();
        BufferedImage bi = VCodeGenerator.outputImage(width, height, code);

        // 设置响应头控制浏览器不要缓存
        response.setDateHeader("expries", -1);
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");

        String accept = request.getHeader("Accept");
        if (TEXT_BASE64.equalsIgnoreCase(accept)) {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            OutputStream b64 = Base64.getEncoder().wrap(os);
            ImageIO.write(bi, JPG, b64);
            String result = os.toString(UTF_8);

            response.setContentType(TEXT_BASE64);
            response.getWriter().write(result);
            response.flushBuffer();
        } else {
            // 设置响应头通知浏览器以图片的形式打开
            response.setContentType("image/jpeg");
            // 将图片流写给浏览器
            ImageIO.write(bi, "jpg", response.getOutputStream());
        }
    }

    @RequestMapping(value = "/login/showImage", method = RequestMethod.POST)
    @ResponseBody
    public ResultDto isShowImage() {
        ResultDto resultDto = new ResultDto();
        Session session = SecurityUtils.getSubject().getSession();
        int errorTimes = 0;
        if (session != null) {
            Object obj = session.getAttribute("login.error.times");
            if (obj != null && obj instanceof Integer) {
                errorTimes = (int) obj;
            }
        }
        resultDto.setData(errorTimes);
        return resultDto;
    }

    @RequestMapping(value = "/login/checkcodeimage", method = RequestMethod.POST)
    @ResponseBody
    public ResultDto checkCodeImage(@RequestBody LoginDataDto loginDataDto) throws ServletException, IOException {
        String validateCode = loginDataDto.getValidateCode();
        if (checkVCode(Integer.parseInt(validateCode))) {
            return new ResultDto(0, messageSource.getMessage(MessagesCodes.SUCCESSFUL_VALIDATE_CODE, null));
        }
        generateNewRandom(); // refresh server side v code
        return ResultDto.createResult(ErrorCodes.ERROR_LOGIN_VALIDATE_CODE_ERR);
    }

    /**
     * @param clientVCode
     * @return
     */
    public static synchronized boolean checkVCode(int clientVCode) {
        int serverVCode = VCodeGenerator.genRandomNum();
        Object random = SecurityUtils.getSubject().getSession().getAttribute(VCODE_KEY);
        if (random != null) {
            serverVCode = Integer.parseInt(random.toString());
        }
        return serverVCode == clientVCode;
    }

    static synchronized String generateNewRandom() {
        final int firstNumber = VCodeGenerator.genRandomNum();
        final int secondNumber = VCodeGenerator.genRandomNum();
        final String operatorStr = VCodeGenerator.genRandomOperatorStr();
        String result = firstNumber + operatorStr + secondNumber + "=?";
        int getVCodeValue = getVCodeValue(firstNumber, secondNumber, operatorStr);
        SecurityUtils.getSubject().getSession().setAttribute(VCODE_KEY, getVCodeValue);
        return result;
    }

    private static int getVCodeValue(int firstNumber, int secondNumber, String operator) {
        int result = 0;
        switch (operator) {
            case "+":
                result = firstNumber + secondNumber;
                break;
            case "-":
                result = firstNumber - secondNumber;
                break;
            default:
                break;
        }
        return result;
    }

}
